﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data;
using System.Data.Common;
using Unknown.Framework.Develop;
using Unknown.Framework.General;
using Unknown.Framework.Injection;

namespace Unknown.Framework.Database
{
    /// <summary>
    /// 数据库处理类
    /// </summary>
    public class DatabaseHandler
    {
        /// <summary>
        /// 实例配置处理
        /// </summary>
        private static InstanceConfigurationHandler _InstanceConfigurationHandler = new InstanceConfigurationHandler();

        /// <summary>
        /// 字典
        /// </summary>
        public static Dictionary<string, InstanceIdentify> Dictionary
        {
            get
            {
                return DatabaseHandler._InstanceConfigurationHandler.Dictionary;
            }
        }
        private static string _DefaultInstance;
        /// <summary>
        /// 默认实例
        /// </summary>
        public static string DefaultInstance
        {
            get
            {
                if (string.IsNullOrEmpty(DatabaseHandler._DefaultInstance))
                {
                    DatabaseHandler._DefaultInstance = "Default";
                }

                return DatabaseHandler._DefaultInstance;
            }
            set
            {
                DatabaseHandler._DefaultInstance = value;
            }
        }

        /// <summary>
        /// 配置
        /// </summary>
        /// <param name="directory">目录</param>
        /// <param name="searchPattern">匹配字符串</param>
        public static void Configuration(string directory, string searchPattern)
        {
            DatabaseHandler._InstanceConfigurationHandler.Build(directory, searchPattern);
        }

        /// <summary>
        /// 配置
        /// </summary>
        /// <param name="directory">目录</param>
        public static void Configuration(string directory)
        {
            DatabaseHandler._InstanceConfigurationHandler.Build(directory);
        }

        /// <summary>
        /// 构建标识
        /// </summary>
        /// <returns>结果</returns>
        public static string BuildIdentify(string identity)
        {
            string result = identity;

            if (string.IsNullOrEmpty(identity))
            {
                result = Guid.NewGuid().ToString("D");
            }

            return result;
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        public DatabaseHandler()
        {
            this.Initialize(string.Empty);
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="instance">实例</param>
        public DatabaseHandler(string instance)
        {
            this.Initialize(instance);
        }

        private InstanceIdentify _InstanceIdentify;
        /// <summary>
        /// 实例
        /// </summary>
        public void Initialize(string instance)
        {
            if (string.IsNullOrEmpty(instance))
            {
                instance = DatabaseHandler.DefaultInstance;
            }

            if (!string.IsNullOrEmpty(instance))
            {
                if (DatabaseHandler._InstanceConfigurationHandler.Dictionary.ContainsKey(instance))
                {
                    this._InstanceIdentify = DatabaseHandler._InstanceConfigurationHandler.Dictionary[instance];
                }
            }
        }

        /// <summary>
        /// 执行
        /// </summary>
        /// <param name="operations">操作集合</param>
        /// <param name="transaction">是否事务处理</param>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2100:检查 SQL 查询是否存在安全漏洞")]
        public void Execute(Collection<Operation> operations, bool transaction)
        {
            if ((this._InstanceIdentify != null) && (operations != null) && (operations.Count > 0))
            {
                DbConnection dbConnection = null;
                DbTransaction dbTransaction = null;
                DbCommand dbCommand = null;
                bool error = false;

                try
                {
                    dbConnection = ObjectFactory.Build(this._InstanceIdentify.Connection) as DbConnection;

                    if (dbConnection != null)
                    {
                        dbConnection.ConnectionString = this._InstanceIdentify.Source;
                        dbConnection.Open();
                        if (transaction)
                        {
                            dbTransaction = dbConnection.BeginTransaction();
                        }

                        dbCommand = dbConnection.CreateCommand();
                        dbCommand.CommandType = CommandType.Text;
                        foreach (Operation operation in operations)
                        {
                            error = false;
                            Parameter currentParameter = null;

                            try
                            {
                                if ((operation != null) && (!string.IsNullOrEmpty(operation.Sql)) && (operation.OperationHandler != null))
                                {
                                    dbCommand.CommandText = operation.Sql;
                                    dbCommand.Parameters.Clear();
                                    if (operation.Parameters != null)
                                    {
                                        foreach (Parameter parameter in operation.Parameters)
                                        {
                                            currentParameter = parameter;

                                            DbParameter dbParameter = dbCommand.CreateParameter();
                                            dbParameter.ParameterName = parameter.Name;
                                            dbParameter.Value = parameter.Value;
                                            object dataType = Enum.Parse(this._InstanceIdentify.TypeEnum, parameter.DataType);
                                            this._InstanceIdentify.TypeProperty.SetValue(dbParameter, dataType, null);

                                            dbCommand.Parameters.Add(dbParameter);
                                        }
                                        currentParameter = null;
                                    }

                                    operation.OperationHandler.Execute(dbCommand);
                                }
                            }
                            catch (Exception executeException)
                            {
                                error = true;

                                Collection<string> remarks = new Collection<string>();
                                remarks.Add(dbConnection.ConnectionString);
                                remarks.Add(operation.Sql);
                                if (currentParameter != null)
                                {
                                    remarks.Add(currentParameter.Name);
                                    remarks.Add(string.Format(Variable.Culture, "{0}", currentParameter.Value));
                                    remarks.Add(currentParameter.DataType);
                                }
                                foreach (Parameter parameter in operation.Parameters)
                                {
                                    remarks.Add(parameter.Name);
                                    remarks.Add(string.Format(Variable.Culture, "{0}", parameter.Value));
                                    remarks.Add(parameter.DataType);
                                }

                                CrashHandlers.Default.Hibernate(executeException, remarks);
                            }

                            if (error)
                            {
                                break;
                            }
                        }

                        if ((transaction) && (dbTransaction != null))
                        {
                            if (error)
                            {
                                dbTransaction.Rollback();
                            }
                            else
                            {
                                dbTransaction.Commit();
                            }
                        }
                    }
                }
                catch (Exception exception)
                {
                    if ((transaction) && (dbTransaction != null))
                    {
                        dbTransaction.Rollback();
                    }

                    Collection<string> remarks = new Collection<string>();
                    remarks.Add(dbConnection.ConnectionString);

                    CrashHandlers.Default.Hibernate(exception, remarks);
                }
                finally
                {
                    if ((dbConnection != null) && (dbConnection.State != ConnectionState.Closed))
                    {
                        dbConnection.Close();
                    }
                }
            }
        }

        /// <summary>
        /// 执行
        /// </summary>
        /// <param name="operations">操作集合</param>
        public void Execute(Collection<Operation> operations)
        {
            this.Execute(operations, false);
        }

        /// <summary>
        /// 执行
        /// </summary>
        /// <param name="operation">操作</param>
        /// <param name="transaction">是否事务处理</param>
        public void Execute(Operation operation, bool transaction)
        {
            Collection<Operation> operations = new Collection<Operation>();
            operations.Add(operation);

            this.Execute(operations, transaction);
        }

        /// <summary>
        /// 执行
        /// </summary>
        /// <param name="operation">操作</param>
        public void Execute(Operation operation)
        {
            this.Execute(operation, false);
        }
    }
}
